package com.leoman.service.impl;

import com.leoman.controller.common.CommonController;
import com.leoman.core.Constant;
import com.leoman.dao.AppUserDao;
import com.leoman.dao.PostDao;
import com.leoman.dao.PostImageDao;
import com.leoman.entity.AppUser;
import com.leoman.entity.Post;
import com.leoman.entity.PostImage;
import com.leoman.exception.ParamErrorException;
import com.leoman.exception.UserNotFindException;
import com.leoman.exception.UserSealStatusException;
import com.leoman.service.PostService;
import com.leoman.utils.QiNiuUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartRequest;

import javax.persistence.Transient;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.List;

/**
 * PostServiceImpl
 * Created by 涂奕恒 on 2016/10/18 0018 下午 3:23.
 */
@Service
public class PostServiceImpl implements PostService {

    @Autowired
    private PostDao postDao;

    @Autowired
    private PostImageDao postImageDao;

    @Autowired
    private AppUserDao appUserDao;

    @Override
    public List<Post> findAll() {
        return postDao.findAll();
    }

    @Override
    public Page<Post> find(int pageNum, int pageSize) {
        return postDao.findAll(new PageRequest(pageNum - 1, pageSize, Sort.Direction.DESC, "id"));
    }

    @Override
    public Page<Post> find(int pageNum) {
        return find(pageNum, Constant.PAGE_DEF_SIZE);
    }

    @Override
    public Post getById(int id) {
        return postDao.findOne(id);
    }

    @Override
    public void deleteById(int id) {
        List<PostImage> list = postImageDao.findListByPostId(id);

        if (null != list && list.size() > 0) {
            for (PostImage postImage : list) {
                if (null != postImage) {
                    QiNiuUtils.delete(postImage.getUrl());

                    postImageDao.delete(postImage);
                }
            }
        }

        postDao.delete(id);
    }

    @Override
    public Post create(Post post) {
        return postDao.save(post);
    }

    @Override
    public Post update(Post post) {
        return postDao.save(post);
    }

    @Override
    @Transactional
    public void deleteAll(int[] ids) {
        for (int id : ids) {
            deleteById(id);
        }
    }

    @Override
    public Page<Post> iPageForApp(final Integer userId, Integer pageNum, Integer pageSize) {
        Integer[] info = CommonController.getPageParams(pageNum, pageSize);

        Page<Post> page = postDao.findAll(new Specification<Post>() {
            @SuppressWarnings("ToArrayCallWithZeroLengthArrayArgument")
            @Override
            public Predicate toPredicate(Root<Post> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                Predicate result = null;
                List<Predicate> predicateList = new ArrayList<>();
                if (null != userId) {
                    Predicate pre = cb.equal(root.get("appUser").get("id").as(Integer.class), userId);
                    predicateList.add(pre);
                }

                Predicate pre1 = cb.equal(root.get("checkStatus").as(Integer.class), Constant.CHECK_STATUS_SUCCESS);
                predicateList.add(pre1);

                if (predicateList.size() > 0) {
                    result = cb.and(predicateList.toArray(new Predicate[]{}));
                }

                if (result != null) {
                    query.where(result);
                }
                return query.getGroupRestriction();
            }

        }, new PageRequest(info[0] - 1, info[1], Sort.Direction.DESC, "id"));

        for (Post post : page.getContent()) {
            post.setAuthorName(post.getAppUser().getNickName());
            post.setAuthorAvatar(post.getAppUser().getAvatar());
            post.setPostImageList(postImageDao.findListByPostId(post.getId()));
        }

        return page;
    }

    @Override
    @Transactional
    public void sendPost(Integer userId, String content, MultipartRequest multipartRequest, Integer imgNum)
            throws ParamErrorException, UserNotFindException, UserSealStatusException {
        if (StringUtils.isBlank(content)) {
            throw new ParamErrorException();
        }

        AppUser appUser = AppUserServiceImpl.getAppUserInfo(userId, appUserDao);

        Post post = new Post();
        post.setAppUser(appUser);
        post.setContent(content);
        post.setCheckStatus(Constant.CHECK_STATUS_DEFAULT);
        post.setCreateTime(System.currentTimeMillis());

        // 保存帖子信息
        postDao.save(post);

        // 保存帖子图片信息
        List<MultipartFile> list = new ArrayList<>();

        if (null != imgNum) {
            MultipartFile multipartFile;
            for (int i = 0; i < imgNum; i++) {
                multipartFile = multipartRequest.getFile("file" + i);
                list.add(multipartFile);
            }
        } else {
            list = multipartRequest.getFiles("file");
        }

        PostImage postImage;
        for (MultipartFile file : list) {
            if (null != file && file.getSize() > 0) {
                postImage = new PostImage();
                postImage.setPost(post);
                postImage.setUrl(QiNiuUtils.upload(file));

                postImageDao.save(postImage);
            }
        }
    }

    @Override
    public Integer findCountWithNewPost(Integer index) {
        return postDao.findListByCreateTime(CommonController.getFirstTime(index)).size();
    }

    @Override
    public List<Post> findListByCheckStatus(Integer checkStatus) {
        return postDao.findListByCheckStatus(checkStatus);
    }

    @Override
    public Page<Post> pageByParams(final String content, final String nickName, final Integer checkStatus, Integer pageNum, Integer pageSize) {
        Integer[] info = CommonController.getPageParams(pageNum, pageSize);

        return postDao.findAll(new Specification<Post>() {
            @SuppressWarnings("ToArrayCallWithZeroLengthArrayArgument")
            @Override
            public Predicate toPredicate(Root<Post> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                Predicate result = null;
                List<Predicate> predicateList = new ArrayList<>();
                if (StringUtils.isNotBlank(content)) {
                    Predicate pre = cb.like(root.get("content").as(String.class), "%" + content + "%");
                    predicateList.add(pre);
                }
                if (StringUtils.isNotBlank(nickName)) {
                    Predicate pre = cb.like(root.get("appUser").get("nickName").as(String.class), "%" + nickName + "%");
                    predicateList.add(pre);
                }
                if (null != checkStatus) {
                    Predicate pre = cb.equal(root.get("checkStatus").as(Integer.class), checkStatus);
                    predicateList.add(pre);
                }

                if (predicateList.size() > 0) {
                    result = cb.and(predicateList.toArray(new Predicate[]{}));
                }

                if (result != null) {
                    query.where(result);
                }
                return query.getGroupRestriction();
            }

        }, new PageRequest(info[0] - 1, info[1], Sort.Direction.ASC, "checkStatus"));
    }

    @Override
    public Integer changePostCheckStatus(Integer[] postIds, Integer status) {
        try {
            Post post;

            for (Integer postId : postIds) {
                post = postDao.findOne(postId);
                if (null != post && !post.getCheckStatus().equals(status)) {
                    post.setCheckStatus(status);
                    post.setUpdateTime(System.currentTimeMillis());

                    postDao.save(post);
                }
            }
            return 1;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    @Override
    @Transient
    public Integer batchDelete(Integer[] postIds) {
        try {
            for (Integer postId : postIds) {
                deleteById(postId);
            }
            return 1;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    @Override
    public Integer deleteByPostId(Integer postId) {
        try {
            deleteById(postId);
            return 1;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
}